<?php

/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/3/14
 * Time: 10:24
 *
 */
class MsggCall
{
    use util_array;
    const STATUS_RUNNING = 'running';

    const STATUS_SUCCESS = 'success';

    const STATUS_COMPLETE_BUSY = 'complete_busy';
    const STATUS_COMPLETE_TIMEOUT = 'complete_timeout';
    const STATUS_COMPLETE_UNANSWERED = 'complete_unanswered';
    const STATUS_COMPLETE_REJECT = 'complete_reject';


    const STATUS_FAILURE = 'failure';

    const STATUS_ERROR = 'error';

    public static function execute($params, $channelConfs = [])
    {
        $result = array('code' => 0, 'msg' => '', 'detail' => array());
        try {
            //check phone
            if (empty($params['phone'])) {
                throw new Exception(MsggItem::ERROR_MSG_ITEM_PARAMS_INVALID . ':phone number is invalid', MsggItem::ERROR_CODE_ITEM_PARAMS_INVALID);
            }
            //check sms template
            if (!($params['media'] = self::getMedia((empty($params['media']) ? null : $params['media'])))) {
                throw new Exception(MsggItem::ERROR_MSG_ITEM_PARAMS_INVALID . ':media is invalid', MsggItem::ERROR_CODE_ITEM_PARAMS_INVALID);
            }
            //begin send by channel conf
            $lastResult = false;
            foreach ($channelConfs as $i => $channelConf) {
                $class = empty($channelConf['class']) ? null : $channelConf['class'];
                switch ($class) {
                    case 'MsggUcpaas':
                        $channelResult = MsggUcpaas::call($params, $channelConf);
                        break;
                    case 'MsggNexmo':
                        $channelResult = MsggNexmo::call($params, $channelConf);
                        break;
                    case 'MsggIhuyi':
                        $channelResult = MsggIhuyi::call($params, $channelConf);
                        break;
                    case 'MsggLinkedsee':
                        $channelResult = MsggLinkedsee::call($params, $channelConf);
                        break;
                    default:
                        try {
                            $channelResult = call_user_func(array($class, 'call'), $params, $channelConf);
                        } catch (Exception $e) {
                            $channelResult = array(
                                'code' => $e->getCode(),
                                'msg' => $e->getMessage()
                            );
                        }
                        break;
                }
                $channelName = implode('_', array(MsggItem::TYPE_CALL, (empty($channelConf['name']) ? 'Channel' . $i : $channelConf['name'])));
                $result['detail'][$channelName] = $channelResult;
                //add log
                $attributes = array(
                    'type' => MsggItem::TYPE_CALL,
                    'params' => $params,
                    'result' => $channelResult,
                    'channel' => $channelName,
                    'ext_id' => isset($channelResult['ext']['id']) ? $channelResult['ext']['id'] : null,
                    'ext_status' => isset($channelResult['ext']['status']) ? $channelResult['ext']['status'] : null,
                    'status' => self::mapCodeStatus($class, $channelResult['code']),
                    'conf' => $channelConf
                );

                $log = MsggChannelLog::build($attributes);
                $result['logs'][] = $log;
                //return result

                if (isset($channelResult['code']) && ($channelResult['code'] == 0)) {
                    $result['ext'] = empty($channelResult['ext']) ? array() : $channelResult['ext'];
                    $lastResult = true;
                    break;
                }
            }
            if (!$lastResult) {
                throw new Exception(MsggItem::ERROR_MSG_GATEWAY_FAILURE, MsggItem::ERROR_CODE_GATEWAY_FAILURE);
            }
        } catch (Exception $e) {
            $result['code'] = MsggItem::ERROR_CODE_GATEWAY_FAILURE;
            $result['msg'] = $e->getMessage();
        }
        return $result;
    }

    private static function getMedia($mediaName)
    {
        $medias = array();
        $items = MsggMedia::model()->findAll();
        foreach ($items as $item) {
            $medias[$item->name] = $item->attributes;
        }
        $media = empty($medias[MsggItem::DEFAULT_KEY]) ? current($medias) : $medias[MsggItem::DEFAULT_KEY];
        if (isset($medias[$mediaName])) {
            $media = $medias[$mediaName];
        }
        return $media;
    }

    public static function mapStatus($status)
    {
        $resStatus = MsggItem::STATUS_ERROR;
        switch ($status) {
            case self::STATUS_RUNNING:
                $resStatus = MsggItem::STATUS_HOOKING;
                break;
            case self::STATUS_COMPLETE_BUSY:
            case self::STATUS_COMPLETE_TIMEOUT:
            case self::STATUS_COMPLETE_UNANSWERED:
            case self::STATUS_COMPLETE_REJECT:
                $resStatus = MsggItem::STATUS_COMPLETE;
                break;
            case self::STATUS_SUCCESS:
                $resStatus = MsggItem::STATUS_SUCCESS;
                break;
            case self::STATUS_FAILURE:
                $resStatus = MsggItem::STATUS_FAILURE;
                break;
            default:
            case self::STATUS_ERROR:
                $resStatus = MsggItem::STATUS_ERROR;
                break;
        }
        return $resStatus;
    }

    public static function mapCodeStatus($channelClass, $code)
    {
        $status = MsggItem::STATUS_FAILURE;
        switch ($channelClass) {
            case 'MsggLinkedsee':
            case 'MsggIhuyi':
                $status = $code == 0 ? MsggItem::STATUS_COMPLETE : MsggItem::STATUS_FAILURE;
                break;
            case 'MsggNexmo':
            case 'MsggUcpaas':
                $status = $code == 0 ? MsggItem::STATUS_HOOKING : MsggItem::STATUS_FAILURE;
                break;
        }

        return $status;
    }

    public static function refreshStatus(MsggItem $msg)
    {
        $status = MsggItem::STATUS_FAILURE;
        $ext_id = $msg->getExtId();
        if ($ext_id != null && !empty($channelLog = MsggChannelLog::model()->findByAttributes(['ext_id' => $ext_id]))) {
            $config = json_decode($channelLog->conf, true);
            $class = self::util_array_get($config, 'class', null);
            $status = $channelLog->status;
            if ($class) {
                if (class_exists($class)) {
                    $available_method = array();
                    foreach (get_class_methods($class) as $method) {
                        $available_methods[strtolower($method)] = $method;
                    }
                    if (empty($available_methods['refreshstatus'])) {
                        Yii::log('refreshStatus method  not exists  in class ' . $class, CLogger::LEVEL_ERROR, 'msggcall.refreshStatus');
                    } else {
                        $ext_Status = call_user_func_array(array($class, 'refreshStatus'), array($channelLog));
                        $status = self::mapStatus($ext_Status);
                        $channelLog->status = $status;
                        $channelLog->ext_status = $ext_Status;
                        $channelLog->save();
                    }
                } else {
                    Yii::log('calss not exists ' . $class . ' log id ' . $channelLog->id, CLogger::LEVEL_ERROR, 'msggcall.refreshStatus');
                }
            }
        }
        return $status;
    }

}